/**
 * Created by FDD on 2017/5/15.
 * @desc PlotDraw
 */
import { Map } from 'ol'
import { Draw as $DrawInteraction, DoubleClickZoom } from 'ol/interaction'
import {
  Style as $Style,
  Icon as $Icon,
  Stroke as $Stroke,
  Fill as $Fill
} from 'ol/style'

import Feature from 'ol/Feature'
import { createBox } from 'ol/interaction/Draw'

import Observable from 'observable-emit'
import { getuuid, MathDistance, bindAll } from '../Utils/utils'
import { BASE_LAYERNAME } from '../Constants'
import { createVectorLayer } from '../Utils/layerUtils'
import PlotTextBox from '../Geometry/Text/PlotTextBox'
import * as Plots from '../Geometry/index'
import * as PlotTypes from '../Utils/PlotTypes'

class PlotDraw extends Observable {
  constructor (map, params) {
    super()
    if (map && map instanceof Map) {
      this.map = map
    } else {
      throw new Error('传入的不是地图对象！')
    }
    this.options = params || {}
    /**
     * 交互点
     * @type {null}
     */
    this.points = null
    /**
     * 当前标绘工具
     * @type {null}
     */
    this.plot = null
    /**
     * 当前要素
     * @type {null}
     */
    this.feature = null
    /**
     * 标绘类型
     * @type {null}
     */
    this.plotType = null
    /**
     * 当前标绘参数
     * @type {null}
     */
    this.plotParams = null
    /**
     * 当前地图视图
     * @type {Element}
     */
    this.mapViewport = this.map.getViewport()
    /**
     * 地图双击交互
     * @type {null}
     */
    this.dblClickZoomInteraction = null

    /**
     * draw交互工具
     * @type {null}
     * @private
     */
    this.drawInteraction_ = null

    /**
     * 创建图层名称
     * @type {string}
     */
    this.layerName = ((this.options && this.options['layerName']) ? this.options['layerName'] : BASE_LAYERNAME)

    bindAll([
      'textAreaDrawEnd',
      'mapFirstClickHandler',
      'mapNextClickHandler',
      'mapDoubleClickHandler',
      'mapMouseMoveHandler'
    ], this)

    /**
     * 当前矢量图层
     * @type {*}
     */
    this.drawLayer = createVectorLayer(this.map, this.layerName, {
      create: true
    })
    this.drawLayer.setZIndex(this.options['zIndex'] || 99)
  }

  /**
   * 创建Plot
   * @param type
   * @param points
   * @param _params
   * @returns {*}
   */
  createPlot (type, points, _params) {
    let params = _params || {}
    switch (type) {
      case PlotTypes.TEXTAREA:
        return 'TextArea'
      case PlotTypes.POINT:
        return new Plots.Point([], points, params)
      case PlotTypes.PENNANT:
        return new Plots.Pennant([], points, params)
      case PlotTypes.POLYLINE:
        return new Plots.Polyline([], points, params)
      case PlotTypes.ARC:
        return new Plots.Arc([], points, params)
      case PlotTypes.CIRCLE:
        return new Plots.Circle([], points, params)
      case PlotTypes.CURVE:
        return new Plots.Curve([], points, params)
      case PlotTypes.FREEHANDLINE:
        return new Plots.FreeHandLine([], points, params)
      case PlotTypes.RECTANGLE:
        return new Plots.RectAngle([], points, params)
      case PlotTypes.ELLIPSE:
        return new Plots.Ellipse([], points, params)
      case PlotTypes.LUNE:
        return new Plots.Lune([], points, params)
      case PlotTypes.SECTOR:
        return new Plots.Sector([], points, params)
      case PlotTypes.CLOSED_CURVE:
        return new Plots.ClosedCurve([], points, params)
      case PlotTypes.POLYGON:
        return new Plots.Polygon([], points, params)
      case PlotTypes.ATTACK_ARROW:
        return new Plots.AttackArrow([], points, params)
      case PlotTypes.FREE_POLYGON:
        return new Plots.FreePolygon([], points, params)
      case PlotTypes.DOUBLE_ARROW:
        return new Plots.DoubleArrow([], points, params)
      case PlotTypes.STRAIGHT_ARROW:
        return new Plots.StraightArrow([], points, params)
      case PlotTypes.FINE_ARROW:
        return new Plots.FineArrow([], points, params)
      case PlotTypes.ASSAULT_DIRECTION:
        return new Plots.AssaultDirection([], points, params)
      case PlotTypes.TAILED_ATTACK_ARROW:
        return new Plots.TailedAttackArrow([], points, params)
      case PlotTypes.SQUAD_COMBAT:
        return new Plots.SquadCombat([], points, params)
      case PlotTypes.TAILED_SQUAD_COMBAT:
        return new Plots.TailedSquadCombat([], points, params)
      case PlotTypes.GATHERING_PLACE:
        return new Plots.GatheringPlace([], points, params)
      case PlotTypes.RECTFLAG:
        return new Plots.RectFlag([], points, params)
      case PlotTypes.TRIANGLEFLAG:
        return new Plots.TriangleFlag([], points, params)
      case PlotTypes.CURVEFLAG:
        return new Plots.CurveFlag([], points, params)
      case PlotTypes.LOCATION:
        return new Plots.Location([], points, params)
      case PlotTypes.TEXTLABEL:
        return new Plots.TextLabel([], points, params)
      case PlotTypes.TWOLINES:
          return new Plots.TwoLines([], points, params)
    }
    return null
  }

  /**
   * 激活工具
   * @param type
   * @param params
   */
  active (type, params = {}) {
    this.disActive()
    this.deactiveMapTools()
    this.plotType = type
    this.plotParams = params
    if (type === PlotTypes.TEXTAREA) {
      this.activeInteraction()
    } else if (Object.keys(PlotTypes).some(key => (PlotTypes[key] === type))) {
      this.map.on('click', this.mapFirstClickHandler)
    } else {
      console.warn('不存在的标绘类型！')
    }
  }

  /**
   * 激活交互工具
   */
  activeInteraction () {
    this.drawInteraction_ = new $DrawInteraction({
      style: new $Style({
        fill: new $Fill({
          color: 'rgba(255, 255, 255, 0.7)'
        }),
        stroke: new $Stroke({
          color: 'rgba(0, 0, 0, 0.15)',
          width: 2
        }),
        image: new $Icon({
          anchor: [1, 1],
          anchorXUnits: 'fraction',
          anchorYUnits: 'fraction',
          opacity: 0.75,
          src: ''
        })
      }),
      type: 'Circle',
      geometryFunction: createBox()
    })
    this.map.addInteraction(this.drawInteraction_)
    this.drawInteraction_.on('drawend', this.textAreaDrawEnd)
  }

  /**
   * 绘制结束
   * @param event
   */
  textAreaDrawEnd (event) {
    if (event && event.feature) {
      this.map.removeInteraction(this.drawInteraction_)
      const extent = event.feature.getGeometry().getExtent()
      const _center = [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2]
      const topLeft = this.map.getPixelFromCoordinate([extent[0], extent[1]])
      const bottomRight = this.map.getPixelFromCoordinate([extent[2], extent[3]])
      const [_width, _height] = [Math.abs(topLeft[0] - bottomRight[0]), Math.abs(topLeft[1] - bottomRight[1])]
      const _plotText = new PlotTextBox({
        id: getuuid(),
        position: _center,
        value: '',
        width: _width,
        height: _height,
        style: {
          width: _width + 'px',
          height: _height + 'px'
        }
      })
      if (this.map && this.map instanceof Map && _plotText) {
        this.map.addOverlay(_plotText)
      } else {
        console.warn('未传入地图对象或者plotText创建失败！')
      }
    } else {
      console.info('未获取到要素！')
    }
  }

  /**
   * 取消激活状态
   */
  disActive () {
    this.removeEventHandlers()
    if (this.drawInteraction_) {
      this.map.removeInteraction(this.drawInteraction_)
      this.drawInteraction_ = null
    }
    this.points = []
    this.plot = null
    this.feature = null
    this.plotType = null
    this.plotParams = null
    this.activateMapTools()
  }

  /**
   * PLOT是否处于激活状态
   * @returns {boolean}
   */
  isDrawing () {
    return !!this.plotType
  }

  /**
   * 地图事件处理
   * 激活工具后第一次点击事件
   * @param event
   */
  mapFirstClickHandler (event) {
    this.map.un('click', this.mapFirstClickHandler)
    this.points.push(event.coordinate)
    this.plot = this.createPlot(this.plotType, this.points, this.plotParams)
    this.feature = new Feature(this.plot)
    this.feature.set('isPlot', true)
    this.drawLayer.getSource().addFeature(this.feature)

    if (this.plotType && this.feature) {
      this.plotParams['plotType'] = this.plotType
      this.feature.setProperties(this.plotParams)
    }

    if (this.plotType === PlotTypes.POINT || this.plotType === PlotTypes.PENNANT || 
      this.plotType === PlotTypes.TEXTLABEL) {
      this.plot.finishDrawing()
      this.drawEnd(event)
    } else {
      this.map.on('click', this.mapNextClickHandler)
      if (!this.plot.freehand) {
        this.map.on('dblclick', this.mapDoubleClickHandler)
      }
      this.map.un('pointermove', this.mapMouseMoveHandler)
      this.map.on('pointermove', this.mapMouseMoveHandler)
    }
    
  }

  /**
   * 地图点击事件处理
   * @param event
   * @returns {boolean}
   */
  mapNextClickHandler (event) {
    if (!this.plot.freehand) {
      if (MathDistance(event.coordinate, this.points[this.points.length - 1]) < 0.0001) {
        return false
      }
    }
    this.points.push(event.coordinate)
    this.plot.setPoints(this.points)
    if (this.plot.fixPointCount === this.plot.getPointCount()) {
      this.mapDoubleClickHandler(event)
    }
    if (this.plot && this.plot.freehand) {
      this.mapDoubleClickHandler(event)
    }
  }

  /**
   * 地图双击事件处理
   * @param event
   */
  mapDoubleClickHandler (event) {
    event.preventDefault()
    this.plot.finishDrawing()
    this.drawEnd(event)
  }

  /**
   * 地图事件处理
   * 鼠标移动事件
   * @param event
   * @returns {boolean}
   */
  mapMouseMoveHandler (event) {
    let coordinate = event.coordinate
    if (MathDistance(coordinate, this.points[this.points.length - 1]) < 0.0001) {
      return false
    }
    if (!this.plot.freehand) {
      let pnts = this.points.concat([coordinate])
      this.plot.setPoints(pnts)
    } else {
      this.points.push(coordinate)
      this.plot.setPoints(this.points)
    }
  }

  /**
   * 移除事件监听
   */
  removeEventHandlers () {
    this.map.un('click', this.mapFirstClickHandler)
    this.map.un('click', this.mapNextClickHandler)
    this.map.un('pointermove', this.mapMouseMoveHandler)
    this.map.un('dblclick', this.mapDoubleClickHandler)
  }

  /**
   * 绘制结束
   */
  drawEnd (event) {
    this.dispatchSync('drawEnd', {
      type: 'drawEnd',
      originalEvent: event,
      feature: this.feature
    })
    if (this.feature && this.options['isClear']) {
      this.drawLayer.getSource().removeFeature(this.feature)
    }
    this.disActive()
  }

  /**
   * 添加要素
   */
  addFeature () {
    this.feature = new Feature(this.plot)
    if (this.feature && this.drawLayer) {
      this.drawLayer.getSource().addFeature(this.feature)
    }
  }

  /**
   * 取消激活地图交互工具
   */
  deactiveMapTools () {
    let interactions = this.map.getInteractions().getArray()
    interactions.every(item => {
      if (item instanceof DoubleClickZoom) {
        this.dblClickZoomInteraction = item
        this.map.removeInteraction(item)
        return false
      } else {
        return true
      }
    })
  }

  /**
   * 激活已取消的地图工具
   * 还原之前状态
   */
  activateMapTools () {
    if (this.dblClickZoomInteraction && this.dblClickZoomInteraction instanceof DoubleClickZoom) {
      this.map.addInteraction(this.dblClickZoomInteraction)
      this.dblClickZoomInteraction = null
    }
  }
}
export default PlotDraw
